'''
Author: duliang thinktanker@163.com
Date: 2023-06-23 08:20:39
LastEditors: duliang thinktanker@163.com
LastEditTime: 2024-06-25 17:29:01
FilePath: 
Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
'''
import ctypes
import os
import threading
import time
import tkinter
from tkinter.messagebox import *
import keyboard
import numpy as np
import pyautogui
from PIL import ImageGrab, Image  # 用于保存屏幕截图
from win32api import GetSystemMetrics
import win32gui, win32ui, win32con
import io
from sql import new_search
'''
设置远程还是本地参数
'''

# paddle.set_device("gpu")
# os.environ['FLAGS_eager_delete_tensor_gb'] = "0.0"
# 模型路径下必须含有model和params文件，如果没有，现在可以自动下载了，不过是最简单的模型
# use_gpu 如果paddle是GPU版本请设置为 True

# 窗口，显示器
dc = win32gui.GetDC(0)
dcObj = win32ui.CreateDCFromHandle(dc)
monitor = (0, 0, GetSystemMetrics(0), GetSystemMetrics(1))
hwnd_from_point = win32gui.WindowFromPoint((0, 0))
# 初始化
local_path = os.path.dirname(__file__)
sajj_handle = win32gui.FindWindow("Chrome_WidgetWin_0", "水安将军")
autoclick = os.path.exists(f"{local_path}{os.sep}appdata{os.sep}auto")
mark = os.path.exists(f"{local_path}{os.sep}appdata{os.sep}mark")
print(autoclick, mark)
REMOTE = os.path.exists(f"{local_path}{os.sep}remote")
if REMOTE:
    import requests
    url = "http://223.68.11.42:8211/ocrsajj"
    # url = "http://192.168.15.16:8211/ocrsajj"
else:
    from paddleocr import PaddleOCR
    cls_model_dir = "./whl/cls/ch/ch_ppocr_mobile_v2.0_cls_infer/"
    # --det_model_dir="./inference/ch_ppocr_mobile_v2.0_det_infer/"     # 检测模型所在文件夹
    det_model_dir = "./whl/det/ch/ch_PP-OCRv4_det_server_infer/"
    # --rec_model_dir="./inference/ch_ppocr_mobile_v2.0_rec_infer/"     # 识别模型所在文件夹
    rec_model_dir = "./whl/rec/ch/ch_PP-OCRv4_rec_server_infer/"
    ocr = PaddleOCR(
        use_angle_cls=False,
        use_gpu=True,
        cls_model_dir=cls_model_dir,  #
        det_model_dir=det_model_dir,  #
        rec_model_dir=rec_model_dir,  #
    )


# 准确的坐标定义
def get_window_rect(hwnd):
    try:
        f = ctypes.windll.dwmapi.DwmGetWindowAttribute
    except WindowsError:
        f = None
    if f:
        rect = ctypes.wintypes.RECT()
        DWMWA_EXTENDED_FRAME_BOUNDS = 9
        f(ctypes.wintypes.HWND(hwnd),
          ctypes.wintypes.DWORD(DWMWA_EXTENDED_FRAME_BOUNDS),
          ctypes.byref(rect), ctypes.sizeof(rect))
        print('窗口位置：{} {} {} {}'.format(
            rect.left, rect.top + (rect.bottom - rect.top) // 4, rect.right,
            rect.bottom))
        offset = (rect.bottom - rect.top) * 1.3 // 4
        return rect.left, rect.top + (
            rect.bottom - rect.top) * 1.3 // 4, rect.right, rect.bottom, offset


def snapshot(className=None, winName=None):
    '''
    可以后台截屏，但不能最小化窗口
    '''
    #获取后台窗口的句柄，注意后台窗口不能最小化
    try:
        hWnd = win32gui.FindWindow(className,
                                   winName)  #窗口的类名可以用Visual Studio的SPY++工具获取
        left, top, right, bot = win32gui.GetWindowRect(hWnd)
        width = right - left
        height = bot - top
        #返回句柄窗口的设备环境，覆盖整个窗口，包括非客户区，标题栏，菜单，边框
        hWndDC = win32gui.GetWindowDC(hWnd)
        #创建设备描述表
        mfcDC = win32ui.CreateDCFromHandle(hWndDC)
        #创建内存设备描述表
        saveDC = mfcDC.CreateCompatibleDC()
        #创建位图对象准备保存图片
        saveBitMap = win32ui.CreateBitmap()
        #为bitmap开辟存储空间
        saveBitMap.CreateCompatibleBitmap(mfcDC, width, height)
        #将截图保存到saveBitMap中
        saveDC.SelectObject(saveBitMap)
        #保存bitmap到内存设备描述表
        saveDC.BitBlt((0, 0), (width, height), mfcDC, (0, 0), win32con.SRCCOPY)
        ###获取位图信息
        bmpinfo = saveBitMap.GetInfo()
        bmpstr = saveBitMap.GetBitmapBits(True)
        #内存释放
        win32gui.DeleteObject(saveBitMap.GetHandle())
        saveDC.DeleteDC()
        mfcDC.DeleteDC()
        win32gui.ReleaseDC(hWnd, hWndDC)
        ###生成图像
        im_PIL = Image.frombuffer('RGB',
                                  (bmpinfo['bmWidth'], bmpinfo['bmHeight']),
                                  bmpstr, 'raw', 'BGRX', 0, 1)
        im_PIL = im_PIL.convert('L')
        im_PIL.save(os.getcwd() + '/pil.jpg')  #保存
        return im_PIL
    except Exception as e:
        print(e)
        return None


def screen_thread():
    # threshold = 127
    while True:
        # keyboard.wait(hotkey="ctrl+alt+a")
        keyboard.wait(hotkey="space")
        now = time.time()
        left, top, right, bottom, offset = get_window_rect(sajj_handle)
        image = ImageGrab.grab(bbox=(left, top, right, bottom))
        # image = snapshot(className='Chrome_WidgetWin_0', winName="水安将军")

        if image:
            questionTxt = {"words_result": []}
            optionTxt = {"words_result": []}
            image = image.convert('L')
            image.save("test1.jpeg")
            binary = []
            for i in range(256):
                if i < 125:
                    binary.append(0)
                else:
                    binary.append(1)
            image = image.point(binary, '1')
            image.save("test2.jpeg")
            results = None
            if REMOTE:
                imgBytes1 = io.BytesIO()
                image.save(imgBytes1, format="jpeg")
                resp = requests.post(url=url,
                                     files={"imgbin": imgBytes1.getvalue()})
                if resp.status_code == 200:
                    results = resp.json()
                    if results:
                        results = results[0]
                        print(results)
            else:
                img_convert_ndarray = np.array(image)
                results = ocr.ocr(img_convert_ndarray)[0]
            if not results:
                print("图片未载入")
                continue
            # 第一条与第二条之间的行距
            h1 = results[1][0][-1][-1] - results[0][0][-1][-1]
            print('h1->', results[1][0][-1][-1], results[0][0][-1][-1], h1)
            questionTxt["words_result"].append({"words": results[0][-1][0]})
            for i in range(2, len(results)):
                # 间隔行距
                h2 = results[i][0][-1][-1] - results[i - 1][0][-1][-1]
                print('h2->', results[i][0][-1][-1], results[i - 1][0][-1][-1],
                      h2)
                # if h2 > h1 or h1 > h2*2:
                try:
                    h2_h1 = round(h2 / h1) if h2 > h1 else round(h1 / h2)
                    if h2_h1 > 1:
                        # print("下面是选项:", results[i:])
                        for answerList in results[i - 1:]:
                            # print(answerList[1][0])
                            # print(answerList[0][0][0])
                            optionTxt['words_result'].append({
                                'words':
                                answerList[1][0],
                                "location": {
                                    'top':
                                    answerList[0][0][1],
                                    'left':
                                    answerList[0][0][0],
                                    'width':
                                    answerList[0][1][0] - answerList[0][0][0],
                                    'height':
                                    answerList[0][2][1] - answerList[0][1][1]
                                }
                            })
                        break
                    else:
                        questionTxt["words_result"].append(
                            {"words": results[i][-1][0]})
                except Exception as e:
                    print(e)
                    if 'zero' in str(e):
                        questionTxt["words_result"].append(
                            {"words": results[i - 1][-1][0]})
                finally:
                    h1 = results[i][0][-1][-1] - results[i - 1][0][-1][-1]
                    print('h1->', results[i][0][-1][-1],
                          results[i - 1][0][-1][-1], h1)

            # print(questionTxt)
            # print(optionTxt)
            x, y = new_search(questionTxt, optionTxt, text, answer_text,
                              autoclick, check)
            if x:
                left, top, right, bottom = win32gui.GetWindowRect(sajj_handle)
                # 输出坐标信息
                # print('窗口左上角坐标：({}, {})'.format(left, top))
                # print('窗口右下角坐标：({}, {})'.format(right, bottom))
                print(f'答案相对坐标：{x}，{y}')
                # 鼠标目标坐标
                targetX = left + x
                targetY = top + y + offset
                # 打开自动点击
                if autoclick:
                    mouse_x, mouse_y = pyautogui.position()
                    pyautogui.moveTo(targetX, targetY)
                    print(mouse_x, mouse_y)
                    pyautogui.click()
                    pyautogui.moveTo(mouse_x, mouse_y)
                    # print('\033[32;40m 用时：', time.time() - now)
                    print(f"\033[0;31m{time.time() - now}\033[0m")
                # 打开标记
                if mark:
                    for _ in range(10):
                        # 画一个小白框
                        dcObj.Rectangle((int(targetX), int(targetY),
                                         int(targetX) + 50, int(targetY) + 50))
                        time.sleep(0.01)
                        win32gui.InvalidateRect(hwnd_from_point, monitor,
                                                True)  # 刷新显示器


root = tkinter.Tk()
changeVar = tkinter.BooleanVar()
checkTextVar = tkinter.StringVar()
changeVar.set(True)
checkTextVar.set("每日答题")
sw = root.winfo_screenwidth()  # 得到屏幕宽度
sh = root.winfo_screenheight()  # 得到屏幕高度
offset = sh // 8 + 50
# offset = sh // 8 + 30
root.title("水安将军辅助")
if sajj_handle:

    def checkClick():
        if changeVar.get():
            checkTextVar.set("每日答题")
        else:
            checkTextVar.set("挑战答题")

    root.title("按空格获取答案")
    left1, top1, right1, bottom1 = win32gui.GetWindowRect(sajj_handle)
    # root = tkinter.Tk()
    root.geometry(f"320x800+{left1+(right1-left1)}+{top1}")
    check = tkinter.Checkbutton(root,
                                variable=changeVar,
                                textvariable=checkTextVar,
                                command=checkClick)
    check.pack()
    text = tkinter.Text(root, width=100, height=5)
    text.pack()
    answer_text = tkinter.Text(root, width=100, font=("黑体", 30), fg="red")
    answer_text.pack()
    question = ""
    th = threading.Thread(target=screen_thread)
    # th.setDaemon(True)
    try:
        th.daemon = True
    except:
        th.setDaemon(True)
    th.start()
    root.mainloop()
else:
    print("打开“水安将军”小程序才能使用")
    ww = 240
    wh = 120
    root.geometry("%dx%d+%d+%d" % (ww, wh, sw // 3, sh // 3))

    def close_window():
        root.destroy()

    label = tkinter.Label(root, text="请打开“水安将军”小程序后运行")
    label.pack(pady=10)

    button = tkinter.Button(root, text="关闭窗口", command=close_window)
    button.pack(pady=30)

    root.mainloop()
